﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Gallio.Framework;
using MbUnit.Framework;
using MbUnit.Framework.ContractVerifiers;
using System.IO;
using PTP.TestUtil; //extension methods

namespace PTP.Core
{
  [TestFixture]
  public class ContainerTest
  {
    [Test]
    [Row(null, 0, ContainerType.Undefined, 0, 0, ExpectedException = typeof(ArgumentNullException))]
    [Row(new byte[] { }, 0, ContainerType.Undefined, 0, 0, ExpectedException = typeof(InvalidContainerException))]
    [Row(new byte[] { 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 0, ContainerType.Undefined, 0, 0, ExpectedException = typeof(InvalidContainerException))]
    //                |Container Length     | |Type     | |Code     | |TransactionID        |
    [Row(new byte[] { 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 0, ContainerType.Undefined, 0, 0)]
    //                |Container Length     | |Type     | |Code     | |TransactionID        |
    [Row(new byte[] { 0x0C, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 0, ContainerType.CommandBlock, 0, 0)]
    //                |Container Length     | |Type     | |Code     | |TransactionID        |
    [Row(new byte[] { 0x0C, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 0, ContainerType.DataBlock, 0, 0)]
    //                |Container Length     | |Type     | |Code     | |TransactionID        |
    [Row(new byte[] { 0x0C, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 0, ContainerType.ResponseBlock, 0, 0)]
    //                |Container Length     | |Type     | |Code     | |TransactionID        |
    [Row(new byte[] { 0x0C, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 0, ContainerType.EventBlock, 0, 0)]
    //                |Container Length     | |Type     | |Code     | |TransactionID        |
    [Row(new byte[] { 0x0C, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00 }, 0, ContainerType.CommandBlock, 4096, 0)]
    //                |Container Length     | |Type     | |Code     | |TransactionID        |
    [Row(new byte[] { 0x0C, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x4E, 0x61, 0xBC, 0x00 }, 0, ContainerType.CommandBlock, 4096, 12345678)]
    //                |Container Length     | |Type     | |Code     | |TransactionID        |
    [Row(new byte[] { 0x0D, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x4E, 0x61, 0xBC, 0x00, 0x00 }, 1, ContainerType.CommandBlock, 4096, 12345678)]
    public void ContainerHeader_ReadStream(byte[] input, int payloadLength, ContainerType containerType, int code, int transactionID)
    {
      MemoryStream s = null;
      if (input != null)
        s = new MemoryStream(input);

      ContainerHeader header = new ContainerHeader(s);
      Assert.AreEqual<int>(payloadLength, header.PayloadLength);
      Assert.AreEqual<ContainerType>(containerType, header.ContainerType);
      Assert.AreEqual<int>(code, header.Code);
      Assert.AreEqual<int>(transactionID, header.TransactionID);
    }

    [Test]
    [PairwiseJoin]
    public void ContainerHeader_WriteBytesReadStream(
      [Column(ContainerType.Undefined, ContainerType.CommandBlock, ContainerType.DataBlock, ContainerType.ResponseBlock, ContainerType.EventBlock)]
      ContainerType containerType,
      [Column(0, 0xff, 0x0100, 0xffffffff)]
      uint code,
      [Column(0, 0xff, 0x0100, 0xfffffffe)]
      uint transactionID)
    {
      //Initialize test data
      ContainerHeader header1 = new ContainerHeader();
      header1.ContainerType = containerType;
      header1.Code = (int)code;
      header1.TransactionID = (int)transactionID;

      //write bytes to buffer
      byte[] result1 = new byte[12];
      header1.WriteBytes(result1);

      //read data from buffer
      MemoryStream s = new MemoryStream(result1);
      ContainerHeader header2 = new ContainerHeader(s);

      //write it back to another buffer
      byte[] result2 = new byte[12];
      header2.WriteBytes(result2);

      Assert.AreElementsEqual<byte>(result1, result2);
    }

    [Test]
    [Row(null, new int[] { }, ExpectedException = typeof(ArgumentNullException))]
    [Row(new byte[] { }, new int[] { })]
    [Row(new byte[] { 0x00, 0x00 }, new int[] { }, ExpectedException = typeof(InvalidContainerException))]
    [Row(new byte[] { 0x00, 0x00, 0x00, 0x00 }, new int[] { 0 })]
    [Row(new byte[] { 0x01, 0x00, 0x00, 0x00 }, new int[] { 1 })]
    [Row(new byte[] { 0x4E, 0x61, 0xBC, 0x00, 0x02, 0x00, 0x00, 0x00 }, new int[] { 12345678, 2 })]
    [Row(new byte[] {
      0x00, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x00,
    }, new int[] { 0, 0, 0, 0, 0 })]
    //PIMA 15740:2000: Response datasets may have at most five parameters
    [Row(new byte[] {
      0x00, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x00,
    }, new int[] { 0, 0, 0, 0, 0, 0 }, ExpectedException = typeof(InvalidContainerException))] 
    public void ResponseBlockContainer_ReadStream(byte[] input, int[] expectedParameters)
    {
      MemoryStream s = null;
      if (input != null)
        s = new MemoryStream(input);

      ContainerHeader dummyHeader = new ContainerHeader();
      dummyHeader.PayloadLength = (input == null) ? 0 : input.Length;

      ResponseBlockContainer response = new ResponseBlockContainer(dummyHeader, s);
      Assert.AreElementsEqual<int>(expectedParameters, response.Parameters);
    }
  }
}
